package com.sojson.util.lock.impl;

import static com.sojson.util.lock.LockUtil.TIMEOUT_LONG;

import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import com.sojson.config.exception.TransErrorCode;
import com.sojson.util.ExpUtil;
import com.sojson.util.SpringUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.lock.CustomLock;
import com.sojson.util.lock.DistributedLockUtilInterface;
import com.sojson.util.lock.LockUtil;

/**
 * Redisson分布式锁工具类实现类<BR>
 * 1.集群会出现多个相同的锁,集群同步延迟,锁创建后其他服务器告诉你没创建,出现多把锁
 * 
 * @author liu
 * @date 2020-11-15
 */
public class DistributedLockRedissonUtilImpl implements DistributedLockUtilInterface {

    private static DistributedLockRedissonUtilImpl dis;
    /** Redisson客户端 */
    static RedissonClient cli = SpringUtil.getBeanByType(RedissonClient.class);

    /**
     * Redisson分布式锁实现类
     * 
     * @author liu
     * @date 2020-11-15
     */
    class CustomLockRedisson implements CustomLock {

        /** 锁对象 */
        private RLock lock;

        public CustomLockRedisson(String lockName) {
            this.lock = cli.getLock(getLockName(lockName));
        }

        /**
         * 在给定的时间内获取锁,如果获取到返回true,超时或者没有获取到返回false
         * 
         * @param timeOutGet    获取锁的超时时间(单位: 秒,不设置为10秒)
         * @param timeOutUse    使用锁的超时时间(单位: 秒,不设置为30秒)
         * @param unit          锁的超时时间单位
         * @return
         * @throws Exception 
         */
        @Override
        public boolean lock(long timeOutGet, long timeOutUse, TimeUnit unit) throws Exception {
            boolean isGetLock = false;
            if (timeOutGet == TIMEOUT_LONG && timeOutUse == TIMEOUT_LONG) {
                lock.lock();
                isGetLock = true;
            } else {
                isGetLock = lock.tryLock(timeOutGet, timeOutUse, unit);
            }

            // 如果获取到了锁就返回
            if (isGetLock) {
                return true;
            }
            // 如果没获取到就抛异常
            ExpUtil.throwEx(TransErrorCode.THREAD_BUSY);
            return false;
        }

        /**
         * 释放锁
         */
        @Override
        public void unlock() {
            boolean heldByCurrentThread = lock.isHeldByCurrentThread();
            if (heldByCurrentThread) {
                lock.unlock();
                return;
            }

            ExpUtil.throwEx(TransErrorCode.UNLOCK_FAIL);
        }

        public String getLockName(String lockName) {
            return LockUtil.CACHE_NAME_PREFIX_LOCK + lockName;
        }
    }

    /**
     * 获取锁对象
     * 
     * @param lockName 锁名称
     * @return
     */
    @Override
    public CustomLock getLock(String lockName) {
        return new CustomLockRedisson(lockName);
    }

    /**
     * 判断一个对象是否是空(空对象)
     * 
     * @param obj
     * @return
     */
    private static boolean isBlankObject(Object obj) {
        return StringUtil.isBlankObject(obj);
    }

    public static DistributedLockRedissonUtilImpl getInstances() {
        if (isBlankObject(dis)) {
            dis = new DistributedLockRedissonUtilImpl();
        }
        return dis;
    }

}